#![allow(unused_assignments)]
#![allow(unused_variables)]

use std::time::Instant;

/// 随着`MAX_COUNT`和`MAX_LOOP_COUNT`的越来越大，性能差异就越明显
/// TODO:  后续添加C/C++对比测试
///
/// const MAX_COUNT: usize = 10240;
/// const MAX_LOOP_COUNT: i32 = 10240000;
/// exec_stack_ref_move()->move_x_times() took 306 mill seconds.
/// exec_stack_object_move()->move_x_times() took 624 mill seconds.
/// exec_heap_ref_move()->move_x_times() took 344 mill seconds.
/// exec_heap_object_move()->move_x_times() took 340 mill seconds.
///
/// const MAX_COUNT: usize = 1024;
/// const MAX_LOOP_COUNT: i32 = 10240000;
/// exec_stack_ref_move()->move_x_times() took 303 mill seconds.
/// exec_stack_object_move()->move_x_times() took 3200 mill seconds.
/// exec_heap_ref_move()->move_x_times() took 338 mill seconds.
/// exec_heap_object_move()->move_x_times() took 338 mill seconds.
const MAX_COUNT: usize = 1024;
const MAX_LOOP_COUNT: i32 = 10240000;

pub fn box_demo() {
  exec_stack_ref_move();
  exec_stack_object_move();
  exec_heap_ref_move();
  exec_heap_object_move(); // 滥用heap后果很严重
}

// #[derive(Clone)]
struct BigObject {
  values: [u8; MAX_COUNT],
}

fn exec_stack_object_move() {
  fn move_x_times(count: i32) {
    fn move_one_time(i: u8, mut p: BigObject) -> BigObject {
      p.values[0] = i;
      return p;
    }
    let mut p = BigObject {
      values: [0; MAX_COUNT],
    };
    for i in 1..count {
      p = move_one_time(0, p);
      // println!("{}:{}", i, tmp.values[0]);
    }
  }
  let now = Instant::now();
  move_x_times(MAX_LOOP_COUNT);
  let elapsed_time = now.elapsed();
  println!(
    "exec_stack_object_move()->move_x_times() took {} mill seconds.",
    elapsed_time.as_millis()
  );
}

fn exec_stack_ref_move() {
  fn move_x_times(count: i32) {
    fn move_one_time(i: u8, p: &mut BigObject) -> &BigObject {
      p.values[0] = i;
      return p;
    }
    let mut tmp;
    let mut p = BigObject {
      values: [0; MAX_COUNT],
    };
    for i in 1..count {
      let ref mut pp = p;
      tmp = move_one_time(0, pp);
      // println!("{}:{}", i, tmp.values[0]);
    }
  }
  let now = Instant::now();
  move_x_times(MAX_LOOP_COUNT);
  let elapsed_time = now.elapsed();
  println!(
    "exec_stack_ref_move()->move_x_times() took {} mill seconds.",
    elapsed_time.as_millis()
  );
}

fn exec_heap_object_move() {
  fn move_x_times(count: i32) {
    fn move_one_time(i: u8, mut p: Box<BigObject>) -> Box<BigObject> {
      p.as_mut().values[0] = i;
      return p;
    }
    let mut p = Box::new(BigObject {
      values: [0; MAX_COUNT],
    });
    for i in 1..count {
      p = move_one_time(0, p);
      // println!("{}:{}", i, tmp.values[0]);
    }
  }
  let now = Instant::now();
  move_x_times(MAX_LOOP_COUNT);
  let elapsed_time = now.elapsed();
  println!(
    "exec_heap_object_move()->move_x_times() took {} mill seconds.",
    elapsed_time.as_millis()
  );
}

fn exec_heap_ref_move() {
  fn move_x_times(count: i32) {
    fn move_one_time(i: u8, p: &mut Box<BigObject>) -> &Box<BigObject> {
      p.as_mut().values[0] = i;
      return p;
    }
    let mut tmp;
    let mut p = Box::new(BigObject {
      values: [0; MAX_COUNT],
    });
    for i in 1..count {
      let ref mut pp = p;
      tmp = move_one_time(0, pp);
      // println!("{}:{}", i, tmp.values[0]);
    }
  }
  let now = Instant::now();
  move_x_times(MAX_LOOP_COUNT);
  let elapsed_time = now.elapsed();
  println!(
    "exec_heap_ref_move()->move_x_times() took {} mill seconds.",
    elapsed_time.as_millis()
  );
}
